#include "demux.h"

Demux::Demux(QObject *parent)
    : QObject{parent}
{
    fmtCtx = avformat_alloc_context();
    pkt = av_packet_alloc();
    yuvFrame = av_frame_alloc();
    rgbFrame = av_frame_alloc();
}

void Demux::setUrl(const QString &url)
{
    _url = url;
}

void Demux::paly()
{
    if(_video.valid()) return;

    if(!init()){
        qDebug()<<"Please open file first.";
        return;
    }

    qDebug()<<"Open file "<<_url<<"done.";
    _isStop = false;

    _video = std::async(
        std::launch::async,
        [this](){
            while(av_read_frame(fmtCtx,pkt)>=0 && !_isStop){
                if(pkt->stream_index == videoStreamIndex){
                    if(avcodec_send_packet(videoCodecCtx,pkt)>=0){
                        int ret;
                        while((ret=avcodec_receive_frame(videoCodecCtx,yuvFrame))>=0){
                            std::unique_lock<std::mutex> lock(pauseMutex);
                            if (isPaused) {
                                pauseCondition.wait(lock);
                            }
                            lock.unlock();

                            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                                return -1;
                            else if (ret < 0) {
                                fprintf(stderr, "Error during decoding\n");
                                exit(1);
                            }
                            sws_scale(img_ctx,
                                      yuvFrame->data,yuvFrame->linesize,
                                      0,videoCodecCtx->height,
                                      rgbFrame->data,rgbFrame->linesize);

                            // 计算当前播放进度
                            int64_t pts = pkt->pts != AV_NOPTS_VALUE ? pkt->pts : pkt->dts;
                            double duration = static_cast<double>(fmtCtx->streams[videoStreamIndex]->time_base.num) / fmtCtx->streams[videoStreamIndex]->time_base.den;
                            double currentTime = static_cast<double>(pts) * duration;
//                            qDebug() <<" 2023.10.12 currentTime: "<< currentTime;
                            emit sendTime(currentTime, _totalDuration);

                            QImage img(out_buffer,
                                       videoCodecCtx->width,videoCodecCtx->height,
                                       QImage::Format_RGB32);
                            emit sendQImage(img);
                            _currentFrameIndex =  pkt->pts;
                            if(_isPreviousFrame) {
                                // 获取当前时间
                                QString currentDateTime = QDateTime::currentDateTime().toString("yyyyMMdd-hh.mm.ss");

                                // 构造文件名
                                QString fileName = QString("D:/Desktop/%1.png").arg(currentDateTime);

                                // 保存文件
                                bool saved = img.save(fileName);

                                if(saved) {
                                    qDebug() << "文件保存成功";
                                } else {
                                    qDebug() << "文件保存失败";
                                }
                                _isPreviousFrame = false;
                            }

                            std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<long long>(30*_speed)));
                        }
                    }
                    av_packet_unref(pkt);
                }
            }
            return 0;
    });

}

void Demux::stop()
{
    if(!_video.valid()) return;

    _isStop = true;
    _video.get();
    _video = std::future<int>();

    fmtCtx=NULL;

    QImage img("D:/Desktop/test.png");
    emit sendQImage(img);
}

void Demux::setPause()
{
    std::unique_lock<std::mutex> lock(pauseMutex);
    isPaused = !isPaused;
    pauseCondition.notify_all();
}

void Demux::setSpeed(const double &speed)
{
    _speed = speed;
    qDebug() <<" 2023.10.12 : "<< speed;
}

void Demux::setPreviousFrame()
{
    _isPreviousFrame = true;
}

void Demux::seekFrame(const bool &isNextFrame)
{
    int64_t targetFrameIndex = _currentFrameIndex;

    targetFrameIndex += isNextFrame ? 10 : - 10;

    if(targetFrameIndex < 0) targetFrameIndex = 0;

    av_seek_frame(fmtCtx, videoStreamIndex, targetFrameIndex, AVSEEK_FLAG_BACKWARD);
}

bool Demux::init()
{
    if(_url.isEmpty()) return false;

    qDebug() <<" 2023.10.12 : "<< _url;
    if(avformat_open_input(&fmtCtx,_url.toLocal8Bit().data(),NULL,NULL)<0){
        printf("Cannot open input file.\n");
        return false;
    }


    if(avformat_find_stream_info(fmtCtx,NULL)<0){
        printf("Cannot find any stream in file.\n");
        return false;
    }

    int streamCnt=fmtCtx->nb_streams;
    for(int i=0;i<streamCnt;i++){
        if(fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
            videoStreamIndex = i;
            continue;
        }
    }

    if(videoStreamIndex==-1){
        printf("Cannot find any stream in file.\n");
        return false;
    }

    // 假设 fmtCtx 是已经打开的 AVFormatContext，videoStreamIndex 是视频流的索引
    int64_t duration = fmtCtx->streams[videoStreamIndex]->duration;
    _totalDuration = static_cast<double>(duration) * av_q2d(fmtCtx->streams[videoStreamIndex]->time_base);
    qDebug() <<" 2023.10.12 totalDuration: "<< _totalDuration;

    //////////////////////视频部分开始/////////////////////////////
    AVCodecParameters *videoCodecPara = fmtCtx->streams[videoStreamIndex]->codecpar;

    if(!(videoCodec = avcodec_find_decoder(videoCodecPara->codec_id))){
        printf("Cannot find valid decode codec.\n");
        return false;
    }

    if(!(videoCodecCtx = avcodec_alloc_context3(videoCodec))){
        printf("Cannot find valid decode codec context.\n");
        return false;
    }

    if(avcodec_parameters_to_context(videoCodecCtx,videoCodecPara)<0){
        printf("Cannot initialize parameters.\n");
        return false;
    }
    if(avcodec_open2(videoCodecCtx,videoCodec,NULL)<0){
        printf("Cannot open codec.\n");
        return false;
    }
    img_ctx = sws_getContext(videoCodecCtx->width,
                             videoCodecCtx->height,
                             videoCodecCtx->pix_fmt,
                             videoCodecCtx->width,
                             videoCodecCtx->height,
                             AV_PIX_FMT_RGB32,
                             SWS_BICUBIC,NULL,NULL,NULL);

    numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB32,videoCodecCtx->width,videoCodecCtx->height,1);
    out_buffer = (unsigned char *)av_malloc(numBytes*sizeof(unsigned char));

    int res = av_image_fill_arrays(
        rgbFrame->data,rgbFrame->linesize,
        out_buffer,AV_PIX_FMT_RGB32,
        videoCodecCtx->width,videoCodecCtx->height,1);
    if(res<0){
        qDebug()<<"Fill arrays failed.";
        return false;
    }
    ///////////////////////////视频部分结束//////////////////////////////////
    return true;
}
